package spring_learn.a15;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;


/*
1. 底层的切点实现
2. 底层的通知实现
3. 底层的切面实现
4. ProxyFactory 用来创建代理
   * 如果指定了接口，且 proxyTargetClass = false，使用 JdkDynamicAopProxy
   * 如果没有指定接口，或者 proxyTargetClass = true，使用 ObjenesisCglibAopProxy
     * 例外：如果目标是接口类型或已经是 Jdk 代理，使用 JdkDynamicAopProxy
 */
public class A15 {


    public static void main(String[] args) {
        /*
            两个切面概念
            aspect =
                通知1(advice) +  切点1(pointcut)
                通知2(advice) +  切点2(pointcut)
                通知3(advice) +  切点3(pointcut)
                ...
            advisor = 更细粒度的切面，包含一个通知和切点
         */

        // 1. 备好切点
        AspectJExpressionPointcut aspectJExpressionPointcut=new AspectJExpressionPointcut();
        aspectJExpressionPointcut.setExpression("execution(* foo())");
        // 2. 备好通知
        MethodInterceptor advice=new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before");
                Object res = invocation.proceed();
                System.out.println("after");
                return res;
            }
        };
        // 3. 备好切面
        DefaultPointcutAdvisor defaultPointcutAdvisor=new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(aspectJExpressionPointcut);
        defaultPointcutAdvisor.setAdvice(advice);
        /*
           4. 创建代理
                a. proxyTargetClass = false, 目标实现了接口, 用 jdk 实现
                b. proxyTargetClass = false,  目标没有实现接口, 用 cglib 实现
                c. proxyTargetClass = true, 总是使用 cglib 实现
         */
        Target2 target2=new Target2();
        ProxyFactory proxyFactory=new ProxyFactory();
        proxyFactory.setTarget(target2);
        proxyFactory.addAdvisor(defaultPointcutAdvisor);
        proxyFactory.setInterfaces(Target2.class.getInterfaces());
        proxyFactory.setProxyTargetClass(true);
        Target2 proxy =(Target2) proxyFactory.getProxy();
        proxy.bar();
        proxy.foo();
        //class spring_learn.a15.A15$Target2$$EnhancerBySpringCGLIB$$e92c6fb3
        System.out.println(proxy.getClass());


        ProxyFactory proxyFactory1=new ProxyFactory();
        Target1 target1=new Target1();
        proxyFactory1.setTarget(target1);
        proxyFactory1.setInterfaces(target1.getClass().getInterfaces());
        proxyFactory1.setProxyTargetClass(false);
        I1 proxy1 =(I1) proxyFactory1.getProxy();
        //class spring_learn.a15.$Proxy0 如果设置的setProxyTargetClass是false
        //class spring_learn.a15.A15$Target1$$EnhancerBySpringCGLIB$$c5520be   如果设置的setProxyTargetClass是true
        System.out.println(proxy1.getClass());
        proxy1.bar();
        proxy1.foo();

        /*
            学到了什么
                a. Spring 的代理选择规则
                b. 底层的切点实现
                c. 底层的通知实现
                d. ProxyFactory 是用来创建代理的核心实现, 用 AopProxyFactory 选择具体代理实现
                    - JdkDynamicAopProxy
                    - ObjenesisCglibAopProxy
         */

    }

    interface I1 {
        void foo();

        void bar();
    }

    static class Target1 implements I1 {
        public void foo() {
            System.out.println("target1 foo");
        }

        public void bar() {
            System.out.println("target1 bar");
        }
    }

    static class Target2 {
        public void foo() {
            System.out.println("target2 foo");
        }

        public void bar() {
            System.out.println("target2 bar");
        }
    }
}
